package cn.iocoder.yudao.module.brokerage.user.dao;

import cn.iocoder.yudao.framework.business.basic.dao.mapper.CoreMapper;
import cn.iocoder.yudao.framework.business.basic.dao.query.CoreLambdaQueryWrapper;
import cn.iocoder.yudao.framework.common.exception.Assertions;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.api.brokerage.level.enums.BrokerageLevelTypeEnum;
import cn.iocoder.yudao.module.api.member.vip.vo.VipUserSummaryVO;
import cn.iocoder.yudao.module.brokerage.user.pojo.bo.BrokerageInviteMonthSummaryBO;
import cn.iocoder.yudao.module.brokerage.user.pojo.po.BrokerageUserDO;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.util.List;

/**
 * 推广用户 Mapper
 *
 * @author 山野羡民
 */
@Mapper
public interface BrokerageUserMapper extends CoreMapper<BrokerageUserDO> {

    default BrokerageUserDO findByUserId(Long userId) {
        CoreLambdaQueryWrapper<BrokerageUserDO> wrapper = new CoreLambdaQueryWrapper<>();
        wrapper.eq(BrokerageUserDO::getUserId, userId);
        wrapper.limitN(1);
        return selectOne(wrapper);
    }

    default int increaseBonusMoney(Long userId, Integer basePrice, Integer bonusMoney) {
        Assertions.isTrue(bonusMoney >= 0, "增加的分佣金额必须大于等于0");
        if (bonusMoney == 0) {
            return 0;
        }
        LambdaUpdateWrapper<BrokerageUserDO> wrapper = new LambdaUpdateWrapper<BrokerageUserDO>()
                .setSql(" achievement_price = achievement_price + " + basePrice
                        + ", bonus_money = bonus_money + " + bonusMoney)
                .eq(BrokerageUserDO::getUserId, userId);
        return update(null, wrapper);
    }

    default int decreaseBonusMoney(Long userId, Integer basePrice, Integer bonusMoney) {
        // 注意：理论上佣金可能已经提现，这时会扣出负数，确保平台不会造成损失
        Assertions.isTrue(bonusMoney >= 0, "减少的分佣金额必须大于等于0");
        if (bonusMoney == 0) {
            return 0;
        }
        LambdaUpdateWrapper<BrokerageUserDO> wrapper = new LambdaUpdateWrapper<BrokerageUserDO>()
                .setSql(" achievement_price = achievement_price - " + basePrice
                        + ", bonus_money = bonus_money - " + bonusMoney)
                .eq(BrokerageUserDO::getUserId, userId);
        return update(null, wrapper);
    }

    default int selectDescendantCount(Long userId) {
        Long aLong = selectCount(new CoreLambdaQueryWrapper<BrokerageUserDO>()
                .apply("FIND_IN_SET({0}, relation_path) > 0", userId));
        if (aLong == null) {
            return 0;
        }
        return aLong.intValue();
    }

    default int selectFatherCount(Long userId) {
        Long aLong = selectCount(new CoreLambdaQueryWrapper<BrokerageUserDO>()
                .eq(BrokerageUserDO::getFatherUserId, userId));
        if (aLong == null) {
            return 0;
        }
        return aLong.intValue();
    }

    default int selectGrandpaCount(Long userId) {
        Long aLong = selectCount(new CoreLambdaQueryWrapper<BrokerageUserDO>()
                .eq(BrokerageUserDO::getGrandpaUserId, userId));
        if (aLong == null) {
            return 0;
        }
        return aLong.intValue();
    }

    @Select("""
            SELECT IFNULL(SUM(IF(`type` = 1, 1, 0)), 0) AS valid_count, IFNULL(SUM(IF(`type` = 0, 1, 0)), 0) AS invalid_count
            FROM brokerage_user
            WHERE deleted = FALSE AND father_user_id = #{userId}
            """)
    VipUserSummaryVO selectVipSummary(@Param("userId") Long userId);

    default PageResult<BrokerageUserDO> selectFatherAndGrandpaPage(Integer current, Integer size, Long userId) {
        CoreLambdaQueryWrapper<BrokerageUserDO> wrapper = new CoreLambdaQueryWrapper<>();
        wrapper.and(w -> w.eq(BrokerageUserDO::getFatherUserId, userId)
                .or().eq(BrokerageUserDO::getGrandpaUserId, userId));
        return selectPage(new PageParam().setPageNo(current).setPageSize(size), wrapper);
    }

    default PageResult<BrokerageUserDO> selectFatherPage(Integer current, Integer size, Long userId) {
        CoreLambdaQueryWrapper<BrokerageUserDO> wrapper = new CoreLambdaQueryWrapper<>();
        wrapper.eq(BrokerageUserDO::getFatherUserId, userId);
        return selectPage(new PageParam().setPageNo(current).setPageSize(size), wrapper);
    }

    default PageResult<BrokerageUserDO> selectGrandpaPage(Integer current, Integer size, Long userId) {
        CoreLambdaQueryWrapper<BrokerageUserDO> wrapper = new CoreLambdaQueryWrapper<>();
        wrapper.eq(BrokerageUserDO::getGrandpaUserId, userId);
        return selectPage(new PageParam().setPageNo(current).setPageSize(size), wrapper);
    }

    default PageResult<BrokerageUserDO> selectAgencyTeamPage(Integer current, Integer size, Long userId) {
        CoreLambdaQueryWrapper<BrokerageUserDO> wrapper = new CoreLambdaQueryWrapper<>();
        wrapper.and(w -> w.eq(BrokerageUserDO::getFatherUserId, userId)
                .or().eq(BrokerageUserDO::getGrandpaUserId, userId));
        wrapper.eq(BrokerageUserDO::getType, BrokerageLevelTypeEnum.AGENCY.getValue());
        return selectPage(new PageParam().setPageNo(current).setPageSize(size), wrapper);
    }


    default PageResult<BrokerageUserDO> selectVipPage(Integer current, Integer size, Long userId, Boolean valid) {
        CoreLambdaQueryWrapper<BrokerageUserDO> wrapper = new CoreLambdaQueryWrapper<>();
        wrapper.eq(BrokerageUserDO::getFatherUserId, userId);
        if (Boolean.TRUE.equals(valid)) {
            wrapper.eq(BrokerageUserDO::getType, BrokerageLevelTypeEnum.VIP.getValue());
        } else if (Boolean.FALSE.equals(valid)) {
            wrapper.eq(BrokerageUserDO::getType, BrokerageLevelTypeEnum.NORMAL.getValue());
        }
        return selectPage(new PageParam().setPageNo(current).setPageSize(size), wrapper);
    }

    @Select("""
            SELECT *
            FROM brokerage_user
            WHERE deleted = FALSE
            AND user_id = #{userId}
            AND YEAR(create_time) = #{year}
            AND MONTH(create_time) = #{month}
            ORDER BY id DESC
            """)
    List<BrokerageUserDO> selectByUserIdAndMonth(@Param("userId") Long userId, @Param("year") int year, @Param("month") int month);

    @Select("""
            SELECT COUNT(user_id) AS invite_count, YEAR(create_time) AS year, MONTH(create_time) AS month
            FROM brokerage_user
            WHERE father_user_id = #{userId}
            AND create_time >= DATE_SUB(CURDATE(), INTERVAL #{limitMonth} MONTH)
            GROUP BY year, month
            ORDER BY year DESC, month DESC
            """)
    List<BrokerageInviteMonthSummaryBO> selectInviteSums(@Param("userId") Long userId, @Param("limitMonth") int limitMonth);

}